package problems;

import interfaces.EulerProblemInterface;

import java.util.LinkedList;
import java.util.List;

import utility.DivisibilityChecker;
import utility.ProblemSpecifics;

public class EulerProblem001 implements EulerProblemInterface {

	private ProblemSpecifics problemSpecifics;
	private List<Integer> listOfNumbersDivisibleBy3Or5;
	private static final int UPPER_BOUNDARY = 1000;
	private static final int FIVE = 5;
	private static final int THREE = 3;

	public EulerProblem001() {
		String problemStatement = "Find the sum of all the multiples of 3 or 5 below 1000.";
		problemSpecifics = new ProblemSpecifics(problemStatement);
		listOfNumbersDivisibleBy3Or5 = new LinkedList<Integer>();
	}

	public void solve() {
		generateListOfNumbersEvenlyDivisibleBy3Or5UpTo1000();
		addAllListItemsToResult();
		markAsSolved();
	}

	private void generateListOfNumbersEvenlyDivisibleBy3Or5UpTo1000() {
		for (int i = 0; i < UPPER_BOUNDARY; i++) {
			addToListIfDivisibleBy3Or5(i);
		}
	}

	private void addToListIfDivisibleBy3Or5(int numberToCheck) {
		if (divisibleBy3or5(numberToCheck)) {
			listOfNumbersDivisibleBy3Or5.add(numberToCheck);
		}
	}

	private void addAllListItemsToResult() {
		for (Integer numberToAdd : listOfNumbersDivisibleBy3Or5) {
			problemSpecifics.addToResult(numberToAdd);
		}
	}

	private boolean divisibleBy3or5(int i) {
		boolean divBy3 = DivisibilityChecker.firstEvenlyDividesSecond(i, THREE);
		boolean divBy5 = DivisibilityChecker.firstEvenlyDividesSecond(i, FIVE);

		boolean evenlyDivisibleByOneOrTheOther = divBy3 || divBy5;

		return evenlyDivisibleByOneOrTheOther;
	}

	public String stateTheProblem() {
		return problemSpecifics.stateTheProblem();
	}

	public long reportResult() {
		return problemSpecifics.reportResult();
	}

	public ProblemStatus reportStatus() {
		boolean isSolved = problemSpecifics.isSolved();
		return new ProblemStatus(isSolved);
	}

	private void markAsSolved() {
		problemSpecifics.markAsSolved();
	}
}
